using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.Xna.Framework.Graphics;
using Color = System.Drawing.Color;
using Rectangle = Microsoft.Xna.Framework.Rectangle;

namespace Pavilion.DesignerTool
{
    public class XnaWindowsFormPanel : Panel
    {
        private bool isValid;

        public XnaWindowsFormPanel() : base()
        {
            if (!DesignMode)
            {
                GraphicsDeviceService.CreateGraphicsDeviceService(Handle);

                BeginDraw();
                EndDraw();
            }
        }

        public bool BeginDraw()
        {
            isValid = ValidateGraphicsDevice();

            if (!isValid)
                return false; ;

            SetVieportToMatchWindowSize();

            GraphicsDeviceService.Instance.GraphicsDevice.Clear(Microsoft.Xna.Framework.Color.LightSteelBlue);
            DrawManager.Instance.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied);

            return true;
        }

        public void EndDraw()
        {
            if (!isValid)
                return;

            try
            {
                Rectangle sourceRectangle = new Rectangle(0, 0, ClientSize.Width, ClientSize.Height);
                GraphicsDeviceService.Instance.GraphicsDevice.Present(sourceRectangle, null, this.Handle);

                DrawManager.Instance.End();
            }
            catch
            {
                int m = 0;
                // Present might throw if the device became lost while we were drawing. The lost device will be handled by the next BeginDraw,
                // so we just swallow the exception.
            }
        }

        private bool ValidateGraphicsDevice()
        {
            if (GraphicsDeviceService.Instance == null)
                return false;

            if (IsDeviceLost)
                return false;

            if (DeviceNeedResetting || IsDeviceBigEnough)
                return ResetDevice();

            return true;
        }

        private void SetVieportToMatchWindowSize()
        {
            Viewport viewport = new Viewport();

            viewport.X = 0;
            viewport.Y = 0;

            viewport.Width = ClientSize.Width;
            viewport.Height = ClientSize.Height;

            viewport.MinDepth = 0;
            viewport.MaxDepth = 1;

            GraphicsDeviceService.Instance.GraphicsDevice.Viewport = viewport;
        }

        private bool ResetDevice()
        {
            try { GraphicsDeviceService.Instance.ResetDevice(ClientSize.Width, ClientSize.Height); }
            catch { return false; }

            return true;
        }

        private bool DeviceNeedResetting { get { return (GraphicsDeviceService.Instance.GraphicsDevice.GraphicsDeviceStatus == GraphicsDeviceStatus.NotReset); } }

        private bool IsDeviceLost { get { return (GraphicsDeviceService.Instance.GraphicsDevice.GraphicsDeviceStatus == GraphicsDeviceStatus.Lost); } }

        private bool IsDeviceBigEnough
        {
            get
            {
                PresentationParameters pp = GraphicsDeviceService.Instance.GraphicsDevice.PresentationParameters;
                return (ClientSize.Width > pp.BackBufferWidth) || (ClientSize.Height > pp.BackBufferHeight);
            }
        }

        /// <summary>
        /// Ignores WinForms paint-background messages. The default implementation
        /// would clear the control to the current background color, causing
        /// flickering when our OnPaint implementation then immediately draws some
        /// other color over the top using the XNA Framework GraphicsDevice.
        /// </summary>
        protected override void OnPaintBackground(PaintEventArgs pevent) { }
    }
}
